package xyz.tanxiao.links.common.listener;

import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import xyz.tanxiao.links.common.enums.LinksCacheKeyEnum;
import xyz.tanxiao.links.common.utils.NetworkUtils;
import xyz.tanxiao.links.entity.SlIpBlacklist;
import xyz.tanxiao.links.entity.SlLinkAccess;
import xyz.tanxiao.links.service.SlIpBlacklistService;
import xyz.tanxiao.links.service.SlLinkAccessService;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 通用事件通知监听
 *
 * @author 万成波
 * @email 2300064869@qq.com
 * @createTime 2023-06-11 04:55:17 星期日
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class CommonEventListener {

	private final ThreadPoolTaskExecutor taskExecutor;

	private final SlLinkAccessService linkAccessService;

	private final SlIpBlacklistService blacklistService;

	private final RedisTemplate<String, Object> redisTemplate;


	/**
	 * 短链接访问事件监听
	 */
	@EventListener(classes = ShortLinkAccessEvent.class)
	public void shortLinkAccessEvent(ShortLinkAccessEvent event) {
		try {
			HttpServletRequest request = NetworkUtils.getHttpServletRequest();
			UserAgent userAgent;
			String accessIp;

			if (Objects.isNull(request)) {
				userAgent = null;
				accessIp = null;
			} else {
				accessIp = NetworkUtils.getRequestIp(request);
				userAgent = UserAgentUtil.parse(request.getHeader("user-agent"));
			}

			this.taskExecutor.execute(() -> {
				// 封装短链接访问信息
				SlLinkAccess linkAccess = new SlLinkAccess();
				linkAccess.setMappingKey(event.getMappingKey());
				linkAccess.setAccessTime(LocalDateTime.now());
				linkAccess.setResult(event.getResult());
				linkAccess.setResultInfo(event.getResultInfo());

				// 填充客户端操作系统信息
				if (Objects.nonNull(userAgent)) {
					linkAccess.setClientInfo(userAgent.getOs().getName() + " " + userAgent.getBrowser().getName());
				}
				// 填充访问ip地址地理位置信息
				if (Objects.nonNull(accessIp)) {
					linkAccess.setAccessIp(accessIp);
					linkAccess.setIpLocation(NetworkUtils.getIpLocation(accessIp));
				}
				this.linkAccessService.save(linkAccess);
			});
		} catch (Exception e) {
			log.error("=> 短链接访问事件错误：{}", e.getMessage());
		}
	}


	/**
	 * 客户端黑名单事件监听
	 */
	@EventListener(classes = SlIpBlacklist.class)
	public void ipBlacklistEvent(SlIpBlacklist blacklist) {
		try {
			this.taskExecutor.execute(() -> {
				// 查询黑名单信息
				SlIpBlacklist dbIpBlacklist = this.blacklistService.getOne(
					Wrappers.lambdaQuery(SlIpBlacklist.class).eq(SlIpBlacklist::getClientIp, blacklist.getClientIp())
				);
				// 添加或更新ip黑名单
				if (Objects.isNull(dbIpBlacklist)) {
					blacklist.setCreateTime(LocalDateTime.now());
					blacklist.setTriggerCount(1);
					this.blacklistService.save(blacklist);
				} else {
					dbIpBlacklist.setTriggerCount(dbIpBlacklist.getTriggerCount() + 1);
					this.blacklistService.updateById(dbIpBlacklist);
				}
			});
		} catch (Exception e) {
			log.error("=> 黑名单事件监听错误：{}", e.getMessage());
		}
	}


	/**
	 * 短链批量生成事件
	 */
	@EventListener(classes = BatchTaskEvent.class)
	public void shortLinkGenerateEvent(BatchTaskEvent task) {
		// 任务状态查询缓存Key
		String cacheKey = LinksCacheKeyEnum.BATCH_TO_LINK_TASK_CACHE_KEY.getCacheKey() + task.getTaskId();

		// 任务状态缓存
		BatchTaskEvent cacheTask = (BatchTaskEvent) this.redisTemplate.opsForValue().get(cacheKey);
		if (Objects.isNull(cacheTask)) {
			cacheTask = task;
		} else {
			cacheTask.setStatus(task.getStatus());
		}

		switch (cacheTask.getStatus()) {
			case 0 : {
				cacheTask.setMessage("短链批量生成中，请耐心等待");
				cacheTask.setStartTime(LocalDateTime.now());
				break;
			}
			case 1 : {
				cacheTask.setMessage("短链数据保存中，请耐心等待");
				break;
			}
			case 2 : {
				cacheTask.setMessage("短链数据导出中，请耐心等待");
				break;
			}
			case 3 : {
				cacheTask.setMessage("短链批量生成完毕");
				cacheTask.setDownloadUrl(task.getDownloadUrl());
				// 计算任务用时
				LocalDateTime endTime = LocalDateTime.now();
				cacheTask.setEndTime(endTime);
				cacheTask.setTaskTime(ChronoUnit.SECONDS.between(cacheTask.getStartTime(), endTime));
				break;
			}
			case 4 : {
				cacheTask.setMessage("短链批量处理失败");
				break;
			}
			default : {
				break;
			}
		}
		this.redisTemplate.opsForValue().set(cacheKey, cacheTask, 10, TimeUnit.MINUTES);
	}

}
